//***************************************************************************//
//*
//* 内容摘要：RTP封装解封装处理
//*	
//* 当前版本：V1.0		
//* 作    者：zhfayuan
//* 完成日期：2016-8-21
//**************************************************************************//
#ifndef __CSDRTP_H__
#define __CSDRTP_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "SDCommDef.h"
#include "SDPacketBuffer.h"


#ifdef WIN32
#ifndef IN_MULTICAST
	#define IN_MULTICAST(ip)    (((ip) & 0xF0000000UL) == 0xE0000000UL)
#endif
#endif

#define RTP_OK		0
#define RTP_ERR		-1

//对于重传包（媒体包、冗余包、握手包均可能被重传）为了同原始包区分开来
//将在原始包payload基础上加上RTP_PAYLOAD_NACK_OFFSET，得到新的payload
#define RTP_PAYLOAD_OFFSET_FOR_NACK				100

//重传包是否使用独立的Payload
#define ENABLE_NACK_WITH_OFFSET_PAYLOAD			1

//心跳握手包是否不走FEC流程，便于实现更灵活的FEC group分配机制
#define HANDLE_PACKET_WITHOUT_FEC				1

//RTP负载payload类型，注意设置为小于RTP_PAYLOAD_NACK_OFFSET
typedef enum
{
	RTP_PAYLOAD_AAC = 12,
	RTP_PAYLOAD_H264 = 14,
	RTP_PAYLOAD_FEC = 16,	
	RTP_PAYLOAD_HANDLE = 22,
	RTP_PAYLOAD_NACK_REQ = 24

}NET_TRANS_TYPE;

//UDP代理模式
#define   ENABLE_UDP_PROXY_MODE				1
#define	  UDP_PROXY_MAGIC_CODE				0x12BA34CD
#define	  UDP_DIRECT_MAGIC_CODE				0xCD34BA21
typedef struct
{
	UINT unMagicCode;
	UINT unTargetIp;
	UINT unTargetPort;
}UDP_PROXY_HEAD;

typedef struct T_rtp_t T_rtp_t;

#define WORDS_SMALLENDIAN
//12字节RTP头
typedef struct T_rtp_header
{
#ifdef WORDS_BIGENDIAN
	unsigned short   v:2;		/* packet type                */
	unsigned short   p:1;		/* padding flag               */
	unsigned short   x:1;		/* header extension flag      */
	unsigned short   cc:4;		/* CSRC count                 */
	unsigned short   m:1;		/* marker bit                 */
	unsigned short   pt:7;		/* payload type               */
#else
	unsigned short   cc:4;		/* CSRC count                 */
	unsigned short   x:1;		/* header extension flag      */
	unsigned short   p:1;		/* padding flag               */
	unsigned short   v:2;		/* packet type                */
	unsigned short   pt:7;		/* payload type               */
	unsigned short   m:1;		/* marker bit                 */
#endif
	UINT16          seq;		/* sequence number            */
	UINT32          ts;			/* timestamp                  */
	UINT32          ssrc;		/* synchronization source     */
	/* The csrc list, header extension and data follow, but can't */
	/* be represented in the struct.                              */
} T_rtp_header;


typedef struct T_socket_udp 
{   
	INT32 	fd;
	
	UINT32	myIP;			/* 本地接收/发送IP */
	UINT32	hisRxIP;		/* 发送时的目的地址*/
	UINT32	hisTxIP;		/* 接收时远端发送IP */
	
	UINT16	myPort;			/* 本地接收/发送端口 */
	UINT16	hisRxPort;		/* 发送时的目的端口*/
	UINT16	hisTxPort;		/* 接收时远端发送端口 */
	unsigned char	 	ttl;
}T_socket_udp;


struct T_rtp_t 
{
	T_socket_udp	*rtp_socket;
	UINT32	my_ssrc;			
};


typedef void * HRTPSESSION; 
typedef void * HRTCPSESSION;


typedef struct T_rtpParam
{
     UINT32  timestamp;
     BOOL    marker;
     BYTE    payload;
    /*贡献源*/
     INT32   cc;
     char*   csrc;
    /*扩展*/
     UINT16  extenType;
     UINT16  extenLen;    
     unsigned char*   exten;

       UINT32  sSrc;
       UINT16  sequenceNumber;
       int     sByte;
       int     len;
} T_rtpParam;


#ifdef WIN32
typedef int socklen_t;
#endif


#ifndef MYSOCKADDR
#define MYSOCKADDR
typedef struct sockaddr_in mysockaddr;
#endif

enum LOST_METHOD_TYPE
{
	//不进行发送端手动丢包
	NO_MANU_LOST = 0,
	//按间隔丢包
	LOST_BY_INTERVAL,
	//按随机比例丢包
	LOST_BY_RANDOM,
	//按间隔连续丢指定包数
	LOST_CONTINUE_BY_INTERVAL
};

#ifdef WIN32
// 均匀分布的随机数
class Random
{
public:
	Random(int size) {
		this->size = 0;
		seeds.resize(size);
	}

	int random() {
		int x, i;
		if (seeds.size() == 0) return 0;
		if (size == 0) { 
			for (i = 0; i < (int)seeds.size(); i++) {
				seeds[i] = i;
			}
			size = (int)seeds.size();
		}
		i = rand() % size;
		x = seeds[i];
		seeds[i] = seeds[--size];
		return x;
	}

protected:
	int size;
	std::vector<int> seeds;
};
#endif

class CSDRtp
{
public:
	CSDRtp(NET_TRANS_TYPE type);
	virtual ~CSDRtp();

	
	INT32 MDrtpSetRemoteRecvAddress(struct sockaddr_in *ptRemoteAddr);
	INT32 MDrtpSetSendTTL(UINT8 ttl);
	void MDrtpSetSocketBuff(int nSocketBuffSize);
	void MDrtpSetSocketBlock(BOOL bSocketInBlockMode);
	INT32 MDrtpRead(void* buf, INT32 len, T_rtpParam* p, struct sockaddr *from, int *fromlen, UINT unTimeOut);
	INT32 MDrtpWrite(void *pInBuf, void *pOutBuf, INT32 len, T_rtpParam *p);
	INT32 MDudpWrite(UINT8 *pInBuf, INT32 len);	
	INT32 MDrtpStart(struct sockaddr_in * ptLocalAddr);
	INT32 MDrtpClose();
	INT32 MDrtpCutConnect(void);

	//强制发送丢包，用于模拟测试
	BOOL ForceSendLost(LOST_METHOD_TYPE eLostMethod, UINT unLostValue, UINT unPacketsLostContinue);

#if ENABLE_UDP_PROXY_MODE
	//告知代理服务器真实的目的地址
	void MDrtpSetProxyRemoteAddress(struct sockaddr_in *ptRemoteAddr);
#endif

private:
	NET_TRANS_TYPE m_type;
	HRTPSESSION m_hRTP;
	//UDP 发送缓冲大小
	int m_iUdpSocketBuffSize;
	//UDP 接收超时（秒）
	int	m_nUdpSocketTimeout; 
	//Socket为阻塞模式还是非阻塞模式
	BOOL m_bSocketInBlockMode;

	//用于模拟丢包测试
	LOST_METHOD_TYPE m_eLostMethodManul;
	UINT m_unLostValueManul;
	UINT m_unLostPacketContinue;
	UINT m_unLostPacketCount;
	UINT m_unCurrSendSeq;
#ifdef WIN32
	Random m_randNumCalc;
#endif
#if ENABLE_UDP_PROXY_MODE
	int m_aunSendTempBuff[2048 / sizeof(int)];
	int m_aunRecvTempBuff[2048 / sizeof(int)];
	UINT m_unProxyRealIp;
	UINT m_unProxyRealPort;
	BOOL m_bHasSetProxyAddr;
#endif

private:
	HRTPSESSION rtpOpen(struct sockaddr_in *ptLocalAddr);
	int rtpCalcsByte( T_rtpParam *p );
	int rtpPack( T_rtp_t *s, void *buf, int len, T_rtpParam *p );
	int rtpUnpack( T_rtp_t *s, char *buf, int len, T_rtpParam *p );

	int rtpSendInit(T_socket_udp * s, UINT32 hisRxIP,UINT16 hisRxPort);
	int rtpRecvInit(T_socket_udp * s, UINT32 myIP,UINT16 myPort);
	int rtpSend( T_socket_udp *s, char *buffer, int buflen );
#if ENABLE_UDP_PROXY_MODE
	int rtpRecv( T_socket_udp *s, char *buffer, int buflen, struct sockaddr *from, int *fromlen, UINT unTimeOut, UINT &unProxyRemoteIp, UINT &unProxyRemotePort);
#else
	int rtpRecv( T_socket_udp *s, char *buffer, int buflen, struct sockaddr *from, int *fromlen
			   , UINT unTimeOut);
#endif
	int rtpExit( T_socket_udp *s );
	int rtpBlock(T_socket_udp *s);
	int rtpUnblock(T_socket_udp *s);
	
};

#ifdef __cplusplus
}
#endif
	
#endif

